/***********************************************************
 * Author: 	Brandon McKune
 * E-Mail:	bmckune.cs@gmail.com
 * Date:	September 2, 2011
 * Class:	CSc 8370 - Data Security
 * Time:	1150 - 1325
 * Smstr:	Fall 2011
 */

#include "MatrixHandler.h"

MatrixHandler::MatrixHandler(){
	m_ui64MatrixRows = 0;
	m_ui64MatrixColumns = 0;
}

MatrixHandler::~MatrixHandler(){
	this->deleteMatrix();
}

bool MatrixHandler::loadMatrix(char* buffer, size_t size, UINT numColumns){
	if(numColumns <= 1){
		fprintf(stderr, "loadMatrix::numColumns < 2, just use buffer passed.");
		return false;
	}

	//Check to make sure matrix is empty.
//	if(this->m_prg2dMatrix != NULL){
//		this->deleteMatrix();
//	}

	this->m_ui64MatrixColumns = numColumns;
	this->m_ui64MatrixRows = size / numColumns;

	if(size % numColumns != 0){
		this->m_ui64MatrixRows++;
	}

	this->m_prg2dMatrix.resize(this->m_ui64MatrixRows);
//	this->m_prg2dMatrix = new char*[this->m_ui64MatrixRows];

	for(UINT i = 0; i < this->m_ui64MatrixRows; i++){
		this->m_prg2dMatrix[i].resize(this->m_ui64MatrixColumns);
//		m_prg2dMatrix[i] = new char[this->m_ui64MatrixColumns];
	}

	UINT temp = m_ui64MatrixRows * m_ui64MatrixColumns;

	if(size > temp){
		return false;
	}
//	Read into rows first.
//	for(UINT i = 0; i < this->m_ui64MatrixRows; i++){
//		for(UINT j = 0; j < this->m_ui64MatrixColumns; j++){
//			if(size < (this->m_ui64MatrixRows*i + j)){
//				this->m_prg2dMatrix[i][j] = '\0';
//			}else{
//				char  temp_char = buffer[this->m_ui64MatrixRows*i + j];
//				if(this->checkValidity(temp_char)){
//					this->m_prg2dMatrix[i][j] = temp_char;
//				}
//			}
//		}
//	}

//	Read into columns first
	for(UINT i = 0; i < this->m_ui64MatrixColumns; i++){
		for(UINT j = 0; j < this->m_ui64MatrixRows; j++){
			if(size < (this->m_ui64MatrixColumns*i + j)){
				this->m_prg2dMatrix[j][i] = '\0';
			}else{
				char  temp_char = buffer[this->m_ui64MatrixColumns*i + j];
				if(this->checkValidity(temp_char)){
					this->m_prg2dMatrix[j][i] = temp_char;
				}
			}
		}
	}

	return true;
}

char MatrixHandler::getElement(uint64_t row, uint64_t column){
	if(row > this->m_ui64MatrixRows || column > this->m_ui64MatrixColumns){
		fprintf(stderr, "Row:Column format exceeds size of matrix.");
		return '\0';
	}

	return this->m_prg2dMatrix[row][column];
}

char* MatrixHandler::transposeMatrix(){
//	if(this->m_prg2dMatrix == NULL){
//		return NULL;
//	}

	UINT size = this->m_ui64MatrixColumns*this->m_ui64MatrixRows + 1;

	//Adding 1 for null terminator
	char *buffer = (char*)malloc(sizeof(char)*size);

	memset(buffer, 'a', size);
	buffer[size - 1] = '\0';

//	Read out columns first
//	for(UINT j = 0; j < this->m_ui64MatrixColumns; j++){
//		for(UINT i = 0; i < this->m_ui64MatrixRows; i++){
//			if(this->m_prg2dMatrix[i][j] == '\0'){
//				buffer[this->m_ui64MatrixRows*j + i] = 0;
//			}else{
//				buffer[this->m_ui64MatrixRows*j + i] = this->m_prg2dMatrix[i][j];
//			}
//		}
//	}

//	//Read out rows first
	for(UINT j = 0; j < this->m_ui64MatrixRows; j++){
		for(UINT i = 0; i < this->m_ui64MatrixColumns; i++){
			if(this->m_prg2dMatrix[j][i] == '\0'){
				buffer[this->m_ui64MatrixColumns*j + i] = 0;
			}else{
				buffer[this->m_ui64MatrixColumns*j + i] = this->m_prg2dMatrix[j][i];
			}
		}
	}

	return buffer;
}

bool MatrixHandler::permuteMatrix(UINT source, UINT destination){
	if(source >= this->m_ui64MatrixColumns || destination >= this->m_ui64MatrixColumns){
		fprintf(stderr, "permuteMatrix:: source or destination > # of columns.");
		return false;
	}

	char* temp_buffer = (char*)malloc(sizeof(char)*this->m_ui64MatrixRows);

	for(UINT i = 0; i < this->m_ui64MatrixRows; i++){
		memcpy(&temp_buffer[i], &this->m_prg2dMatrix[i][destination], sizeof(char));
	}

	for(UINT i = 0; i < this->m_ui64MatrixRows; i++){
		memcpy(&this->m_prg2dMatrix[i][destination], &this->m_prg2dMatrix[i][source], sizeof(char));
	}

	for(UINT i = 0; i < this->m_ui64MatrixRows; i++){
		memcpy(&this->m_prg2dMatrix[i][source], &temp_buffer[i], sizeof(char));
	}

	free(temp_buffer);

	return true;
}

void MatrixHandler::printMatrix(){
	for(uint64_t i = 0; i < this->m_ui64MatrixRows; i++){
		for(uint64_t j = 0; j < this->m_ui64MatrixColumns; j++){
			if(this->m_prg2dMatrix[i][j] == NULL){
				printf("%c", '0');
			}else{
				printf("%c", this->m_prg2dMatrix[i][j]);
			}
		}
		printf("\n");
	}
}

/***********************************************************
 * Protected Functional Members
 */
bool MatrixHandler::deleteMatrix(){
//	if(this->m_prg2dMatrix != NULL){
//		//for(uint64_t i = 0; i < m_ui64MatrixRows; i++){
//			delete [] *m_prg2dMatrix;
//		//}
//		delete [] m_prg2dMatrix;
//	}
//
//	return true;
}

bool MatrixHandler::checkValidity(char charToCheck){
	if(charToCheck < 48){ //"Corresponds to '/' character in ascii chart
		return false;
	}else if(charToCheck >= 58 && charToCheck < 65){
		return false;
	}else if(charToCheck >= 91 && charToCheck < 97){
		return false;
	}else if(charToCheck >= 123 && charToCheck < 128){
		return false;
	}else if(charToCheck == '\0'){
		return true;
	}

	return true;
}
